package io.gitee.cdw.sensitive.util;

import io.gitee.cdw.sensitive.model.SensitiveConst;
import org.apache.commons.lang3.StringUtils;

/**
 * 数据脱敏的工具类
 *
 * @author Created by chendw on 2023/5/6 14:32.
 */
public class SensitiveInfoUtils {

    private SensitiveInfoUtils() {
    }

    /**
     * 对字符串进行脱敏操作
     *
     * @param origin          原始字符串
     * @param prefixNoMaskLen 左侧需要保留几位明文字段
     * @param suffixNoMaskLen 右侧需要保留几位明文字段
     * @param maskStr         用于遮罩的字符串, 如'*'
     * @return 脱敏后结果
     */
    public static String desValue(String origin, int prefixNoMaskLen, int suffixNoMaskLen, String maskStr) {
        if (origin == null) {
            return null;
        }
        if (prefixNoMaskLen + suffixNoMaskLen >= origin.length()) {
            suffixNoMaskLen = 0;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0, n = origin.length(); i < n; i++) {
            if (i < prefixNoMaskLen || i > (n - suffixNoMaskLen - 1)) {
                sb.append(origin.charAt(i));
                continue;
            }
            sb.append(maskStr);
        }
        return sb.toString();
    }

    /**
     * [中文姓名] 只显示第一(showLength)个汉字，其他隐藏为2个星号<例子：李*杰>
     */
    public static String chineseName(final String fullName) {
        int prefixNoMaskLen = StringUtils.length(fullName) <= 2 ? 0 : 1;
        return desValue(fullName, prefixNoMaskLen, 1, SensitiveConst.SENSITIVE_MASK_CHAR);
    }

    /**
     * 密码脱敏，只显示 6 个  *
     *
     * @param password 密码
     * @return 脱敏后的数据
     */
    public static String password(final String password) {
        if (StringUtils.isBlank(password)) {
            return "";
        }
        return getSensitiveInfo(6);
    }

    /**
     * [身份证号] 显示最后四位，其他隐藏。共计18位或者15位。<例子：*************5762>
     */
    public static String idCard(String id) {
        return desValue(id, 6, 4, SensitiveConst.SENSITIVE_MASK_CHAR);
    }

    /**
     * [身份证号] 显示最后四位，其他隐藏。共计18位或者15位。<例子：*************5762>
     */
    public static String custom(final String text, int begin, int end) {
        if (StringUtils.isBlank(text)) {
            return "";
        }
        return StringUtils.left(text, begin).concat(StringUtils.removeStart(
                StringUtils.leftPad(StringUtils.right(text, end), StringUtils.length(text), "*"), "******"));
    }

    /**
     * [固定电话] 后四位，其他隐藏<例子：****1234>
     */
    public static String fixedPhone(final String num, int end) {
        if (StringUtils.isBlank(num)) {
            return "";
        }
        return StringUtils.leftPad(StringUtils.right(num, end), StringUtils.length(num), SensitiveConst.SENSITIVE_MASK_CHAR);
    }

    /**
     * [手机号码] 前三位，后四位，其他隐藏<例子:138****1234>
     */
    public static String mobilePhone(final String mobile) {
        return desValue(mobile, 3, 4, SensitiveConst.SENSITIVE_MASK_CHAR);

    }

    /**
     * [地址] 只显示到地区，不显示详细地址；我们要对个人信息增强保护<例子：北京市海淀区****>
     *
     * @param sensitiveBeginSize 敏感信息的长度
     */
    public static String address(final String address, final int sensitiveBeginSize) {
        if (StringUtils.isBlank(address)) {
            return "";
        }
        final int length = StringUtils.length(address);

        return StringUtils.rightPad(StringUtils.left(address, length - sensitiveBeginSize), length, SensitiveConst.SENSITIVE_MASK_CHAR);

    }

    /**
     * [电子邮箱] 邮箱前缀仅显示第一个字母，前缀其他隐藏，用星号代替，@及后面的地址显示<例子:g**@163.com>
     */
    public static String email(final String email, int begin) {
        if (StringUtils.isBlank(email)) {
            return "";
        }
        final int index = StringUtils.indexOf(email, "@");
        if (index <= begin) {
            return email;
        } else {
            return StringUtils.rightPad(StringUtils.left(email, begin), index, SensitiveConst.SENSITIVE_MASK_CHAR)
                    .concat(StringUtils.mid(email, index, StringUtils.length(email)));
        }
    }

    /**
     * [银行卡号] 前六位，后四位，其他用星号隐藏每位1个星号<例子:6222600**********1234>
     */
    public static String bankCard(final String cardNum, int begin, int end) {
        if (StringUtils.isBlank(cardNum)) {
            return "";
        }
        if (getSensitive(cardNum, begin, end)) {
            begin = 4;
            end = 6;
        }
        return StringUtils.left(cardNum, begin).concat(StringUtils.removeStart(
                StringUtils.leftPad(StringUtils.right(cardNum, end), StringUtils.length(cardNum), SensitiveConst.SENSITIVE_MASK_CHAR),
                getSensitiveInfo(begin)));
    }

    /**
     * 根据正则脱敏
     *
     * @param context     内容
     * @param pattern     正则
     * @param replaceChar 替换后的字符
     * @return 脱敏后的数据
     */
    public static String patternReplace(final String context, String pattern, String replaceChar) {
        if (context == null) {
            return null;
        }
        return context.replaceAll(pattern, replaceChar);
    }

    /**
     * 获取总的长度
     *
     * @param begin 开始显示的长度
     * @param end   结尾显示的长度
     * @return 总要显示的长度
     */
    private static int getAllLength(int begin, int end) {
        return begin + end;
    }

    /**
     * 判断前端传来的长度，是否比 当前字符的长度大
     *
     * @param address            地址
     * @param sensitiveBeginSize 开始长度
     * @param sensitiveEndSize   结尾长度
     * @return
     */
    private static boolean getSensitive(final String address, final int sensitiveBeginSize,
                                        final int sensitiveEndSize) {
        int showLength = getAllLength(sensitiveBeginSize, sensitiveEndSize);
        int length = StringUtils.length(address);
        if (showLength > length) {
            return false;
        }
        return true;
    }

    /**
     * 显示多少个 *
     *
     * @param length 显示的长度
     * @return 返回组装后的长度
     */
    private static String getSensitiveInfo(int length) {
        return StringUtils.repeat(SensitiveConst.SENSITIVE_MASK_CHAR, length);
    }

}